import {
  BadRequestException,
  HttpException,
  HttpStatus,
  Injectable,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { JwtService } from '@nestjs/jwt';
import { getRepository, Repository } from 'typeorm';
import { ApiTypeGetReqDto, ApiTypeGetResDto } from '../types';
import { PageEnum } from '@/types/enums/page.enum';
import { Model, Types } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { ITypeEntity, ITypeEntityField } from '../types/type/superType.type';
import { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
import { RequestBodyObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface';
import { IContentTypeEnctype } from '../types/schemas/type.schema';
import { ApiTypeImportFromOpenApiReqDto } from '../types/dto/openapi.dto';

const formatOpenApiType = {
  string: 'string',
  integer: 'number',
  long: 'number',
  float: 'number',
  double: 'number',
  byte: 'string', // byte	base64 encoded characters，base64 编码字符
  binary: 'string', //	binary	any sequence of octets
  boolean: 'boolean',
  date: 'string', //	date	参考 RFC3339 - full-date
  dateTime: 'string', // date-time	参考 RFC3339 - date-time
  password: 'string', // password	UI 提示隐藏输入
};

@Injectable()
export class DataSourceService {
  constructor(@InjectModel('type') private typeModel: Model<ITypeEntity>) {}

  async importTypesFromOpenapi(
    params: ApiTypeImportFromOpenApiReqDto,
    user_id: number,
    shop_id: number,
  ) {
    const { docItem, openDocument, preview } = params;
    console.log('openDocument: ', openDocument);
    if (!openDocument && (!docItem || !docItem.apiDocStr)) {
      throw new BadRequestException('请补充Openapi文档内容');
    }
    let data = openDocument;
    if (docItem?.apiDocStr) {
      try {
        data = JSON.parse(docItem.apiDocStr) as OpenAPIV3.Document;
      } catch (error) {
        throw new BadRequestException('JSON解析失败');
      }
    }

    const projectId = params.projectId || docItem?.projectId;
    if (!projectId) throw new BadRequestException('Projct Cant Empty');
    const fkId = docItem?._id || projectId;

    const { paths, components } = data;

    const { schemas } = components;
    // 接口文档信息存入
    // docItem.host = host;
    // docItem.basePath = basePath;

    // 查询现有接口与类型
    const types = await this.typeModel.find({
      fkId,
    });

    const schemaToField = (
      name: string,
      schema: OpenAPIV3.SchemaObject,
      {
        requiredKeys,
        importType,
      }: {
        /**
         * 上一级Schema的required，用于判断本字段是否必选
         */
        requiredKeys?: string[];

        /**
         * 本级类型引用
         * "attribute": {
         *   "$ref": "#/components/schemas/StateChange"
         * },
         */
        importType?: ITypeEntity;
      },
    ) => {
      // console.log('[schemaToField 111] ', schema);
      const {
        type,
        description,
        required,
        default: _default,
        enum: _enum,
        example,
        // schema,
        // $ref,
      } = schema;
      // sortInfos: { type: 'array', items: { $ref: '#/definitions/SortInfo' } },
      // manyFieldMatchingKeys: { type: 'array', items: { type: 'string' } },
      let _importType: ITypeEntity = importType; // object 类型引用
      let { items } = schema as OpenAPIV3.ArraySchemaObject;
      if (items && (items as OpenAPIV3.ReferenceObject).$ref) {
        const { schema, importType } = schemaNameToVoType(
          (items as OpenAPIV3.ReferenceObject).$ref,
        );
        if (schema.type !== 'object') {
          throw new BadRequestException('出现非object类型');
        }
        items = schema;
        _importType = importType;
      }
      // 判断类型-如果是数组则类型为数组中元素的类型
      const _type =
        type === 'array'
          ? (items as OpenAPIV3.NonArraySchemaObject).type
          : type;
      if (name === 'info') {
      }
      const field: ITypeEntityField = {
        type: _type === 'integer' ? 'number' : _type,
        name,
        desc: schema.title || description,
        tip: schema.title ? description : null,
        required: (requiredKeys || []).includes(name),
        default: _default,
        example,
        isArray: type === 'array',
        import: _importType?._id,
      };
      if (schema.properties && typeof schema.properties === 'object' && Object.keys(schema.properties).length > 0) {
        field.fields = objectSchemaToFields(schema.properties, schema);
      }
      // @ts-ignore
      if (schema.type === 'array' && typeof schema.items === 'object' && schema.items?.type === 'object' && Object.keys(schema.items?.properties || {}).length > 0) {
        // @ts-ignore
        field.fields = objectSchemaToFields(schema.items.properties, schema);
        console.log('field.fields: ', field.fields);
      }
      // 枚举
      if (_enum && _enum.length > 0) {
        field.enums = _enum.map((item: string) => ({
          type: typeof item === 'number' ? 'number' : 'string',
          label: String(item),
          value: item,
        }));
      }
      return field;
    };

    const parameterToField = (parameter: OpenAPIV3.ParameterObject) => {
      // if (parameter.in === 'body')
      //   console.log('[parameterToField parameter] ', parameter);
      let importTypeId = '';
      const schemaRef = (parameter.schema as OpenAPIV3.ReferenceObject).$ref;
      if (schemaRef) {
        const { schema, importType } = schemaNameToVoType(schemaRef);
        importTypeId = importType._id;
        parameter.schema = schema;
      }
      const {
        name,
        description,
        required,
        example,
        // enum: enums,
        schema,
        // $ref,
      } = parameter;
      // sortInfos: { type: 'array', items: { $ref: '#/definitions/SortInfo' } },
      // manyFieldMatchingKeys: { type: 'array', items: { type: 'string' } },

      // console.log('[example] ', example);
      const {
        type,
        default: _default,
        enum: _enum,
      } = schema as OpenAPIV3.SchemaObject;
      let { items } = schema as OpenAPIV3.ArraySchemaObject;

      if (items && (items as OpenAPIV3.ReferenceObject).$ref) {
        const { schema, importType } = schemaNameToVoType(
          (items as OpenAPIV3.ReferenceObject).$ref,
        );
        if (schema.type !== 'object') {
          throw new BadRequestException('出现非object类型');
        }
        items = schema;
        importTypeId = importType._id;
      }

      const _type =
        type === 'array'
          ? (items as OpenAPIV3.NonArraySchemaObject)?.type
          : type;

      // console.log('[name] ', name);
      const field: ITypeEntityField = {
        type: _type === 'integer' ? 'number' : _type,
        name,
        desc: description,
        required,
        default: _default,
        example,
        isArray: type === 'array',
        import: importTypeId || undefined,
      };
      // 枚举
      if (_enum && _enum.length > 0) {
        field.enums = _enum.map((item: string) => ({
          type: typeof item === 'number' ? 'number' : 'string',
          label: String(item),
          value: item,
        }));
      }
      return field;
    };

    // 待导入API
    // 待导入数据类型
    const voTypes: ITypeEntity[] = [];
    const apiTypes: ITypeEntity[] = [];
    // 函数
    const schemaNameToVoType = ($ref: string) => {
      // console.log('[schemaNameToVoType] ', $ref);
      const refName = decodeURIComponent(
        $ref.split('#/components/schemas/')[1],
      );
      const schema = schemas[refName] as OpenAPIV3.SchemaObject;
      const importType = schemaToVoType(refName);
      return {
        schema,
        importType,
      };
    };
    const objectSchemaToFields = function (properties, schema) {
      return Object.keys(properties || {}).map((name) => {
        let property = properties[name] as OpenAPIV3.SchemaObject;
        let _importType: ITypeEntity;
        // 判断components.schemas[name].propertiers[name].$ref
        const $ref = (properties[name] as OpenAPIV3.ReferenceObject).$ref;
        if ($ref) {
          const { schema, importType } = schemaNameToVoType($ref);
          property = schema;
          _importType = importType;
        }
        const field = schemaToField(name, property, {
          requiredKeys: schema.required,
          importType: _importType,
        });
        if (field.name === 'media') {
          console.log('[media] ', field);
        }
        return field;
      });
    };
    const schemaToVoType = (name: string) => {
      if (!schemas[name]) return;
      const schema = schemas[name] as OpenAPIV3.SchemaObject;
      const { type, properties, title, description, required } = schema;
      // 去重
      const unikey = fkId + '_' + name;
      const existTypeItem = voTypes.find((item) => unikey === item.unikey);
      if (existTypeItem) return existTypeItem;
      const typeItem: ITypeEntity = {
        _id: new Types.ObjectId(),
        type: 'vo',
        name,
        desc: description || title || name,
        fkId,
        unikey,
        projectId,
        userId: user_id,
        teamId: shop_id,
      };
      voTypes.push(typeItem);
      typeItem.fields = objectSchemaToFields(properties, schema);
      // 根据unikey查询是否已存在
      const existTypeInDb = types.find((item) => item.unikey === unikey);
      if (existTypeInDb) typeItem._id = existTypeInDb._id;
      return typeItem;
    };
    // 生成类型
    Object.keys(schemas || {}).forEach((name, index) => {
      schemaToVoType(name);
    });
    // 生成API
    Object.keys(paths || {}).forEach((path) => {
      const item = paths[path];
      const methods = Object.keys(item);
      methods.forEach((method) => {
        // const method = [0] as keyof OpenAPIV2.HttpMethods;

        const operation = item[method] as OpenAPIV3.OperationObject;
        const desc = operation.summary;
        const { tags, requestBody, responses } = operation;

        //   properties: {
        //     designateFieldAccurateSearch: { type: 'object' },
        //     designateFieldFuzzySearch: {
        //       type: 'object',
        //       additionalProperties: { type: 'string' }, // 用ts表达则是 { [propName: string]: string }
        //     },
        //     manyFieldMatchingKeys: { type: 'array', items: { type: 'string' } },
        //     manyFieldMatchingValue: { type: 'string' },
        //     sortInfos: { type: 'array', items: { $ref: '#/definitions/SortInfo' } },
        //   },
        // "responses": {
        //   "200": {
        //     "description": "OK",
        //     "schema": {
        //       "type": "object",
        //       "additionalProperties": {
        //         "type": "array",
        //         "items": { "$ref": "#/definitions/VarietyOfDishes" } @TODO: 需要支持这种类型，{ [propName: string]: VarietyOfDishes[] }
        //       }
        //     }
        //   }
        // },

        const parseResponses = () => {
          const responses = operation.responses;
          return Object.keys(responses || {})
            .filter((_) => (responses[_] as OpenAPIV3.ResponseObject).content)
            .map((statusCode) => {
              const res = responses[statusCode] as OpenAPIV3.ResponseObject;
              if ((responses[statusCode] as OpenAPIV3.ReferenceObject).$ref) {
                throw new BadRequestException('parseResponses #1');
              }
              let importTypeId = '';
              const mediaTypeObject = res.content;
              let media = mediaTypeObject['application/json'];
              if (!media) {
                if (mediaTypeObject['*/*']) {
                  media = mediaTypeObject['*/*'];
                }
              }
              let schema = media?.schema as OpenAPIV3.SchemaObject; // @TODO: 需要考虑其他类型的返回值
              const examples = media.examples;
              if ((schema as OpenAPIV3.ReferenceObject)?.$ref) {
                const { schema: _schema, importType } = schemaNameToVoType(
                  (schema as OpenAPIV3.ReferenceObject).$ref,
                );
                schema = _schema;
                importTypeId = importType._id;
              }
              const isArray = schema.type === 'array';
              let properties = schema.properties;

              let type = (
                typeof schema.type === 'string' ? schema.type : undefined
              ) as ITypeEntityField['type'];

              if (schema.type === 'array') {
                const itemsRef = (schema.items as OpenAPIV3.ReferenceObject)
                  .$ref;
                if (itemsRef) {
                  const { schema: _refSchema, importType } =
                    schemaNameToVoType(itemsRef);
                  schema.items = _refSchema;
                  // 挂载依赖import
                  importTypeId = importType._id;
                }
                const items = schema.items as OpenAPIV3.SchemaObject;
                if (items.type) {
                  type = items.type as ITypeEntityField['type'];
                  properties = items.properties;
                }
              }
              // if (typeof schema.type !== 'string')
              //   throw new BadRequestException('看看这里3');
              const field: ITypeEntityField = {
                name: statusCode,
                desc: res.description,
                type,
                import: importTypeId || undefined,
                isArray,
                fields: importTypeId
                  ? []
                  : Object.keys(properties || {}).map((name) => {
                      let property = properties[name] as OpenAPIV3.SchemaObject;
                      let _importType: ITypeEntity;
                      // 判断components.schemas[name].propertiers[name].$ref
                      const $ref = (
                        properties[name] as OpenAPIV3.ReferenceObject
                      ).$ref;
                      if ($ref) {
                        const { schema, importType } = schemaNameToVoType($ref);
                        property = schema;
                        _importType = importType;
                      }
                      // console.log('[property] ', property);
                      const field = schemaToField(name, property, {
                        requiredKeys: schema.required,
                        importType: _importType,
                      });
                      return field;
                    }),
                apiExamples: examples as any,
              };
              return field;
            });
          return [];
        };

        // 创建API类型
        const parametersToFields = (
          parameters: (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[],
          field: 'body' | 'path' | 'query' | 'formData' | 'header',
        ) => {
          return parameters
            .filter(
              (_) =>
                !!(_ as OpenAPIV3.ReferenceObject).$ref ||
                (_ as OpenAPIV3.ParameterObject).in === field,
            )
            .map((parameter) => {
              if ((parameter as OpenAPIV3.ReferenceObject).$ref) {
                throw new BadRequestException('这里注意一下 #11');
              }
              const field = parameterToField(
                parameter as OpenAPIV3.ParameterObject,
              );
              return field;
            });
        };

        const unikey = fkId + '_' + path + '_' + method;
        let contentType = 'JSON';
        let enctype: IContentTypeEnctype = 'multipart/form-data';
        // application/json 处理
        const requestBodyFields: ITypeEntityField[] = [];
        if (requestBody) {
          const { content } = requestBody as RequestBodyObject;
          const contentMedia =
            content['application/json'] ||
            content['multipart/form-data'] ||
            content['application/x-www-form-urlencoded'];
          if (content && contentMedia) {
            contentType = 'JSON';
            let importType: ITypeEntity;
            let paramsSchema = contentMedia.schema as OpenAPIV3.SchemaObject;
            const paramsSchemaRef = (paramsSchema as OpenAPIV3.ReferenceObject)
              .$ref;
            if (paramsSchemaRef) {
              const { schema: _refSchema, importType: _importType } =
                schemaNameToVoType(paramsSchemaRef);
              paramsSchema = _refSchema;
              importType = _importType;
            }
            if (paramsSchema) {
              // console.log('[contentMedia] ', contentMedia);
              // console.log('[paramsSchema] ', paramsSchema);
              // 挂载依赖import
              // importTypeId = importType._id;
              const field: ITypeEntityField = {
                name: '_root_',
                desc: '根节点',
                type: paramsSchema.type as
                  | 'string'
                  | 'number'
                  | 'boolean'
                  | 'object',
                import: importType?._id || undefined,
                isArray: paramsSchema.type === 'array',
                example: contentMedia.example,
                fields: importType
                  ? []
                  : Object.keys(
                      typeof paramsSchema.properties === 'object'
                        ? paramsSchema.properties
                        : {},
                    ).map((name) => {
                      const { properties, required } =
                        paramsSchema as OpenAPIV3.SchemaObject;
                      let property = properties[name] as OpenAPIV3.SchemaObject;
                      let _importType: ITypeEntity;
                      // 判断components.schemas[name].propertiers[name].$ref
                      const $ref = (
                        properties[name] as OpenAPIV3.ReferenceObject
                      ).$ref;
                      if ($ref) {
                        const { schema, importType } = schemaNameToVoType($ref);
                        property = schema;
                        _importType = importType;
                      }
                      // console.log('[property] ', property);
                      const field = schemaToField(name, property, {
                        requiredKeys: required,
                        importType: _importType,
                      });
                      return field;
                    }),
              };
              requestBodyFields.push(field);
            }
          }
          // form-data 处理
          if (
            content &&
            (content['multipart/form-data'] ||
              content['application/x-www-form-urlencoded'])
          ) {
            contentType = 'FORM';
            // @TODO: 缺少对text/plain类型的支持
            enctype = content['multipart/form-data']
              ? 'multipart/form-data'
              : 'application/x-www-form-urlencoded';
          }
        }
        if (path === '/system_user_phone') {
          // console.log('requestBodyFields: ', requestBodyFields);
        }
        const apiTypeItem: ITypeEntity = {
          type: 'api',
          name: path,
          desc,
          contentType,
          method: String(method).toUpperCase(),
          uri: path,
          folder: tags?.length > 0 ? tags[0] : undefined,
          params:
            requestBodyFields.length > 0
              ? requestBodyFields
              : operation.parameters
              ? parametersToFields(operation.parameters, 'body')
              : [],
          headers: operation.parameters
            ? parametersToFields(operation.parameters, 'header')
            : [],
          query: operation.parameters
            ? parametersToFields(operation.parameters, 'query')
            : [],
          pathParams: operation.parameters
            ? parametersToFields(operation.parameters, 'path')
            : [],
          fields: parseResponses(),
          extends: {
            enctype,
          },
          fkId,
          unikey,
          projectId,
          userId: user_id,
          teamId: shop_id,
        };

        // 根据unikey查询是否已存在,如果存在从已存在字段内读取用例
        const existTypeInDb = types.find((item) => item.unikey === unikey);
        if (existTypeInDb) {
          const { cases } = existTypeInDb;
          // console.log('[existTypeInDb._id] ', existTypeInDb._id, unikey);
          apiTypeItem._id = existTypeInDb._id;
          if (cases) apiTypeItem.cases = cases;
        }
        apiTypes.push(apiTypeItem);
        // console.log('[apiTypes.length] ', apiTypes.length);
      });
    });
    // 保存 @TODO: 做一下批量保存就好了
    // console.log('[voTypes] ', voTypes);
    if (!preview) {
      const existTypeIds = types.map((_) => _._id);
      const allTypes = [...voTypes, ...apiTypes];
      for (let i = 0; i < allTypes.length; i++) {
        const { _id, ...data } = allTypes[i];
        if (existTypeIds.includes(_id)) {
          data.update_time = Date.now();
          await this.typeModel.updateOne({ _id }, data);
        } else {
          const type = new this.typeModel(allTypes[i]);
          await type.save();
        }
      }
    }
    // 保存文档
    if (docItem?._id) {
      await this.typeModel.updateOne({ _id: docItem._id }, docItem);
    }
    return {
      voTypes,
      apiTypes,
    };
  }

  async importApiFromOpenapiV2(
    docItem: ITypeEntity,
    user_id: number,
    shop_id: number,
  ) {
    if (!docItem || !docItem.apiDocStr)
      throw new BadRequestException('请补充Openapi文档内容');
    const { paths, definitions, host, basePath } = JSON.parse(
      docItem.apiDocStr,
    ) as OpenAPIV2.Document;
    // 接口文档信息存入
    docItem.host = host;
    docItem.basePath = basePath;

    // 查询现有接口与类型
    const types = await this.typeModel.find({
      fkId: docItem._id,
    });

    const parameterToField = (parameter: OpenAPIV2.Parameter) => {
      // console.log('[parameter 111] ', parameter);
      const {
        name,
        description,
        required,
        type,
        items,
        enum: enums,
        schema,
        $ref,
      } = parameter;
      // sortInfos: { type: 'array', items: { $ref: '#/definitions/SortInfo' } },
      // manyFieldMatchingKeys: { type: 'array', items: { type: 'string' } },
      // console.log('[parameter] ', parameter);
      const field: ITypeEntityField = {
        type:
          type === 'integer' ? 'number' : type === 'array' ? items.type : type,
        name,
        desc: description,
        required,
        default: parameter.default,
        isArray: type === 'array',
      };
      // 引用
      if ($ref || (items && items.$ref) || schema) {
        // 从引用类型中补充type
        let ref = $ref;
        if (schema && schema.$ref) {
          ref = schema.$ref;
        }
        if (schema && schema.type === 'array' && schema.items) {
          if (schema.items.$ref) ref = schema.items.$ref;
          field.isArray = true;
        }
        if (items && items.$ref) {
          ref = items.$ref;
        }
        if (ref) {
          const { definition, importType } = definitionNameToVoType(ref);
          field.type =
            typeof definition.type === 'string'
              ? (definition.type as any)
              : 'object';
          field.import = importType._id;
        }
      }
      // 枚举
      if (enums && enums.length > 0) {
        field.enums = enums.map((item) => ({
          type: typeof item,
          label: String(item),
          value: item,
        }));
      }
      return field;
    };

    // 待导入API
    // 待导入数据类型
    const voTypes: ITypeEntity[] = [];
    const apiTypes: ITypeEntity[] = [];
    // 函数
    const definitionNameToVoType = ($ref: string) => {
      const refName = $ref.split('#/definitions/')[1];
      const definition = definitions[refName];
      const importType = definitionToVoType(refName);
      return {
        definition,
        importType,
      };
    };
    const definitionToVoType = (name: string) => {
      if (!definitions[name]) return;
      const { type, properties, title, description, items, required } =
        definitions[name];
      // 去重
      const unikey = docItem._id + '_' + name;
      const existTypeItem = voTypes.find((item) => unikey === item.unikey);
      if (existTypeItem) return existTypeItem;
      // 创新
      const typeItem: ITypeEntity = {
        _id: new Types.ObjectId(),
        type: 'vo',
        name: title,
        desc: description,
        fields: Object.keys(properties || {}).map((name) => {
          const property = properties[name];
          // console.log('[property] ', property);
          if (typeof property.type !== 'string' && !property.$ref)
            throw new BadRequestException('看看这里2');
          const parameter: OpenAPIV2.Parameter = {
            in: '',
            name,
            description: property.description,
            required: required ? required.includes(name) : false,
            type: typeof property.type === 'string' ? property.type : undefined,
            items: property.items,
            enum: property.enum,
            $ref: property.$ref,
          };
          return parameterToField(parameter);
        }),
        fkId: docItem._id,
        unikey,
        projectId: docItem.projectId,
        userId: user_id,
        teamId: shop_id,
      };
      // 根据unikey查询是否已存在
      const existTypeInDb = types.find((item) => item.unikey === unikey);
      if (existTypeInDb) typeItem._id = existTypeInDb._id;
      voTypes.push(typeItem);
      return typeItem;
    };
    // 生成类型
    Object.keys(definitions || {}).forEach((name) => {
      definitionToVoType(name);
    });
    // 生成API
    Object.keys(paths || {}).forEach((path) => {
      const item = paths[path];
      const methods = Object.keys(item);
      methods.forEach((method) => {
        // const method = [0] as keyof OpenAPIV2.HttpMethods;

        const operation = item[method] as OpenAPIV2.OperationObject;
        const desc = operation.summary;
        const { consumes, tags } = operation;

        //   properties: {
        //     designateFieldAccurateSearch: { type: 'object' },
        //     designateFieldFuzzySearch: {
        //       type: 'object',
        //       additionalProperties: { type: 'string' }, // 用ts表达则是 { [propName: string]: string }
        //     },
        //     manyFieldMatchingKeys: { type: 'array', items: { type: 'string' } },
        //     manyFieldMatchingValue: { type: 'string' },
        //     sortInfos: { type: 'array', items: { $ref: '#/definitions/SortInfo' } },
        //   },
        // "responses": {
        //   "200": {
        //     "description": "OK",
        //     "schema": {
        //       "type": "object",
        //       "additionalProperties": {
        //         "type": "array",
        //         "items": { "$ref": "#/definitions/VarietyOfDishes" } @TODO: 需要支持这种类型，{ [propName: string]: VarietyOfDishes[] }
        //       }
        //     }
        //   }
        // },

        const parseResponses = () => {
          const responses = operation.responses;
          return Object.keys(responses || {}).map((statusCode) => {
            const res = responses[statusCode] as OpenAPIV2.ResponseObject;
            let importTypeId = '';
            let schema = res.schema as OpenAPIV2.SchemaObject;
            if (schema?.$ref) {
              const { definition, importType } = definitionNameToVoType(
                schema.$ref,
              );
              schema = definition;
              importTypeId = importType._id;
            }
            const isArray = schema.type === 'array';
            let properties: { [propName: string]: OpenAPIV2.SchemaObject } = {};
            let type = (
              typeof schema.type === 'string' ? schema.type : undefined
            ) as ITypeEntityField['type'];

            if (schema.type === 'array') {
              if (schema.items.$ref) {
                const { definition, importType } = definitionNameToVoType(
                  schema.items.$ref,
                );
                if (!Array.isArray(definition.type)) {
                  importTypeId = importType._id;
                  type = (
                    typeof definition.type === 'string'
                      ? definition.type
                      : definition.type[0]
                  ) as ITypeEntityField['type'];
                  properties = definition.properties;
                }
              } else {
                const items = schema.items as OpenAPIV2.ItemsObject;
                if (items.type) {
                  type = items.type as ITypeEntityField['type'];
                }
              }
            }
            if (typeof schema.type !== 'string')
              throw new BadRequestException('看看这里3');
            const field: ITypeEntityField = {
              name: statusCode,
              desc: res.description,
              type,
              import: importTypeId || undefined,
              isArray,
              fields: importTypeId
                ? []
                : Object.keys(properties).map((name) => {
                    const property = properties[name];
                    if (typeof property.type !== 'string') {
                      throw new BadRequestException('看看这里2');
                    }
                    const parameter: OpenAPIV2.Parameter = {
                      in: '',
                      name,
                      description: property.description,
                      required: !!property.required,
                      type: property.type,
                      items: property.items,
                      enum: property.enum,
                      $ref: property.$ref,
                    };
                    return parameterToField(parameter);
                  }),
            };
            return field;
          });
          return [];
        };

        // 创建API类型
        const parametersToFields = (
          parameters: OpenAPIV2.Parameters,
          field: 'body' | 'path' | 'query' | 'formData' | 'header',
        ) => {
          return operation.parameters
            .filter((_) => !!_.$ref || (_ as OpenAPIV2.Parameter).in === field)
            .map((parameter) => {
              if (parameter.$ref) {
                throw new BadRequestException('这里注意一下');
                parameter = parameter as OpenAPIV2.Parameter;
              } else {
                parameter = parameter as OpenAPIV2.Parameter;
              }
              const field = parameterToField(parameter);
              return field;
            });
        };
        const unikey = docItem._id + '_' + operation.operationId;
        const apiTypeItem: ITypeEntity = {
          type: 'api',
          name: path,
          desc,
          method: String(method).toUpperCase(),
          uri: path,
          params: operation.parameters
            ? parametersToFields(operation.parameters, 'body')
            : [],
          headers: operation.parameters
            ? parametersToFields(operation.parameters, 'header')
            : [],
          query: operation.parameters
            ? parametersToFields(operation.parameters, 'query')
            : [],
          pathParams: operation.parameters
            ? parametersToFields(operation.parameters, 'path')
            : [],
          fields: parseResponses(),
          folder: tags.length > 0 ? tags[0] : undefined,
          fkId: docItem._id,
          unikey,
          projectId: docItem.projectId,
          userId: user_id,
          teamId: shop_id,
        };
        // application/json 处理
        if (consumes[0] === 'application/json') {
          apiTypeItem.contentType = 'JSON';
        }
        // 根据unikey查询是否已存在,如果存在从已存在字段内读取用例
        const existTypeInDb = types.find((item) => item.unikey === unikey);
        if (existTypeInDb) {
          const { cases } = existTypeInDb;
          apiTypeItem._id = existTypeInDb._id;
          if (cases) apiTypeItem.cases = cases;
        }
        apiTypes.push(apiTypeItem);
      });
    });
    // 保存 @TODO: 做一下批量保存就好了
    // console.log('[voTypes] ', voTypes);
    const existTypeIds = types.map((_) => _._id);
    for (let i = 0; i < voTypes.length; i++) {
      const { _id, ...data } = voTypes[i];
      if (existTypeIds.includes(_id)) {
        data.update_time = Date.now();
        const updateRes = await this.typeModel.updateOne({ _id }, data);
        // console.log('[updateRes] ', updateRes);
      } else {
        const type = new this.typeModel(voTypes[i]);
        await type.save();
      }
    }
    // console.log('[apiTypes] ', apiTypes);
    for (let i = 0; i < apiTypes.length; i++) {
      const { _id, ...data } = apiTypes[i];
      if (existTypeIds.includes(_id)) {
        data.update_time = Date.now();
        const updateRes = await this.typeModel.updateOne({ _id }, data);
        // console.log('[updateRes] ', updateRes);
      } else {
        const type = new this.typeModel(apiTypes[i]);
        await type.save();
      }
    }
    // 保存文档
    await this.typeModel.updateOne({ _id: docItem._id }, docItem);
    return {
      voTypes,
      apiTypes,
    };
  }
}
